#include "Card.h"


char Card::valueRanks[] = { '2', '3', '4', '5', '6', '7', '8', '9', 'T',
   'J', 'Q', 'K', 'A', 'X'};

Card::Suit Card::suitRanks[4] = {Card::clubs, Card::diamonds, Card::hearts,
   Card::spades};
int Card::numValsInOrderingArray = 13;


Card::Card(char value, Suit suit)
{
   // because mutator sets errorFlag, we don't have to test
   set(value, suit);
}
string Card::toString()
{
   string retVal;
   char strVal[2];

   if (errorFlag)
      return "** illegal **";
   if (state == deleted)
      return "( deleted )";

   // else implied

   if (value != 'X')
   {
      // not a joker
      // convert char to a CString, then string
      strVal[0] = value;
      strVal[1] = '\0';
      retVal = string(strVal);

      if (suit == spades)
         retVal += " of Spades";
      else if (suit == hearts)
         retVal += " of Hearts";
      else if (suit == diamonds)
         retVal += " of Diamonds";
      else if (suit == clubs)
         retVal += " of Clubs";
   }
   else
   {
      // joker
      retVal = "joker";

      if (suit == clubs)
         retVal += " 1";
      else if (suit == diamonds)
         retVal += " 2";
      else if (suit == hearts)
         retVal += " 3";
      else if (suit == spades)
         retVal += " 4";
   }

   return retVal;
}

// mutator
bool Card::set(char value, Suit suit)
{
   char upVal;

   // convert to uppercase to simplify (need #include <cctype>)
   upVal = toupper((int)value);

   // check for validity
   if (
      upVal == 'A' || upVal == 'K'
      || upVal == 'Q' || upVal == 'J'
      || upVal == 'T' || upVal == 'X'
      || (upVal >= '2' && upVal <= '9')
      )
   {
      errorFlag = false;
      state = active;
      this->suit = suit;
      this->value = upVal;
      return true;
   }
   else
   {
      errorFlag = true;
      return false;
   }
}

void Card::setState( Card::State state)
{
   this->state = state;
}

// accessors
char Card::getVal()
{
   return value;
}

Card::Suit Card::getSuit()
{
   return suit;
}

Card::State Card::getState()
{
   return state;
}

bool Card::getErrorFlag()
{
   return errorFlag;
}

bool Card::equals(Card card)
{
   if (this->value != card.value)
      return false;
   if (this->suit != card.suit)
      return false;
   if (this->deleted != card.deleted)
      return false;
   if (this->state != card.state)
      return false;
   return true;
}

// sort methods in Card
void Card::setRankingOrder( char valueOrderArr[], Suit suitOrdeArr[],
      int numValsInOrderingArray  )
{
   int k;

   // expects valueOrderArr[] to contain only cards used per pack,
   // including jokers, needed to define order for the game environment

   if (numValsInOrderingArray  < 0 || numValsInOrderingArray  > 13)
      return;

   Card::numValsInOrderingArray = numValsInOrderingArray;

   for (k = 0; k < numValsInOrderingArray ; k++)
      Card::valueRanks[k] = valueOrderArr[k];

   for (k = 0; k < 4; k++)
      Card::suitRanks[k] = suitOrdeArr[k];
}

int Card::getSuitRank(Suit st)
{
   int k;

   for (k = 0; k < 4; k++)
      if (suitRanks[k] == st)
         return k;

   // should not happen
   return 0;
}

int Card::getValueRank(char val)
{
   int k;

   for (k = 0; k < numValsInOrderingArray; k++)
      if (valueRanks[k] == val)
         return k;

   // should not happen
   return 0;
}

void Card::arraySort(Card array[], int arraySize)
{
    for (int k = 0; k < arraySize; k++)
       if (!floatLargestToTop(array, arraySize - 1 - k))
          return;
}

bool Card::floatLargestToTop(Card array[], int top)
{
   bool changed = false;
   
   for (int k = 0; k < top; k++)
      if (array[k].compareTo(array[k+1]) > 0)
      {
         swap(array[k], array[k+1]);
         changed = true;
      };
   return changed;
}

void Card::swap(Card &a, Card &b)
{
   Card temp;

   temp = a;
   a = b;;
   b = temp;
}
 
int Card::compareTo(Card &other)
{
   if (this->value == other.value)
      return ( getSuitRank(this->suit) - getSuitRank(other.suit) );

   return (
      getValueRank(this->value)
         - getValueRank(other.value)
      );
}